#pragma once
#include<iostream>
#include<string>
#include<fstream>
#include<memory>
#include<ctime>
#include<sstream>
#include<filesystem>
#include<unistd.h>
#include"Lock.hpp"
namespace LogModule
{
    using namespace LockModule;
    const std::string defaultpath="./log/";
    const std::string defaultname="log.txt";
    enum class LogLevel
    {
        DEBUG,
        INFO,
        WARNING,
        ERROR,
        FATAL
    };
    std::string LogLevelToString(LogLevel level)
    {
        switch(level)
        {
            case LogLevel::DEBUG:return "DEBUG";
            case LogLevel::INFO:return "INFO";
            case LogLevel::WARNING:return "WARNING";
            case LogLevel::ERROR:return "ERROR";
            case LogLevel::FATAL:return "FATAL";
            default:return "UNKNOWN";
        }
        return "UNKNOWN";
    }
    std::string GetCurrTime()
    {
        time_t tm=time(nullptr);
        struct tm curr;
        localtime_r(&tm,&curr);
        char timebuffer[64];
        snprintf(timebuffer,sizeof(timebuffer),"%4d-%02d-%02d:%02d:%02d:%02d",
                curr.tm_year+1900,
                curr.tm_mon+1,
                curr.tm_mday,
                curr.tm_hour,
                curr.tm_min,
                curr.tm_sec);
        return timebuffer;
    }

    //策略模式，策略接口
    class LogStrategy
    {
        public:
        virtual ~LogStrategy()=default;
        virtual void Synclog(const std::string Message)=0;
    };

    //控制台日志策略，在控制台打印消息
    class ConsoleLogStrategy:public LogStrategy
    {
        public:
        void Synclog(const std::string Message) override
        {
            LockGuard lockguard(_mutex);
            std::cerr<<Message<<std::endl;
        }
        private:
        Mutex _mutex;
    };
    class FileLogStrategy:public LogStrategy
    {
        public:
        FileLogStrategy(const std::string logpath=defaultpath,const std::string logname=defaultname)
        :_logpath(logpath),_logfilename(logname)
        {
            LockGuard guard(_mutex);
            if(std::filesystem::exists(_logpath))
                return;
            try
            {
                std::filesystem::create_directories(_logpath);
            }
            catch(const std::filesystem::filesystem_error& e)
            {
                std::cerr << e.what() << '\n';
            }
        }
        void Synclog(const std::string Message) override
        {
            LockGuard lockguard(_mutex);
            std::string log=_logpath+_logfilename;
            std::ofstream out(log.c_str(),std::ios::app);
            if(!out.is_open())
                return;
            out<<Message<<'\n';
            return;
        }
        private:
        std::string _logpath;
        std::string _logfilename;
        Mutex _mutex;
    };

    class Logger
    {
        public:
        Logger()
        {
            UseConsoleStrategy();
        }
        void UseConsoleStrategy()
        {
            //unique_ptr不支持拷贝构造以及常规赋值，但是可以移动赋值
            //通过创建新的unique_ptr，释放旧的资源，接管新资源
            _strategy=std::make_unique<ConsoleLogStrategy>();
        }
         void UseFileStrategy()
        {
            _strategy=std::make_unique<FileLogStrategy>();
        }
        class LogMessage
        {
            private:
            LogLevel _type;
            std::string _curr_time;
            pid_t _pid;
            std::string _filename;
            int _line;
            Logger& _logger;
            std::string _log_info;
            
            public:
            LogMessage(LogLevel type,std::string& filename,int line,Logger& logger)
            :_type(type),_curr_time(GetCurrTime()),_pid(getpid()),_filename(filename),_line(line),_logger(logger)
            {
                std::stringstream ssbuffer;
                ssbuffer<<"["<<_curr_time<<"]"
                        <<"["<<LogLevelToString(_type)<<"]"
                        <<"["<<_pid<<"]"
                        <<"["<<_filename<<"]"
                        <<"["<<_line<<"]"
                        <<"-";
                _log_info=ssbuffer.str();
            }
            template<typename T>
            LogMessage& operator<<(const T& info)
            {
                std::stringstream ssbuffer;
                ssbuffer<<info;
                _log_info+=ssbuffer.str();
                return *this;
            }
            ~LogMessage()
            {
                if(_logger._strategy)
                    _logger._strategy->Synclog(_log_info);
            }
        };
        LogMessage operator()(LogLevel type,std::string filename,int line)
        {
            return LogMessage(type,filename,line,*this);
        }
        private:
        std::unique_ptr<LogStrategy> _strategy;
    };

    //定义全局logger对象
    Logger logger;

#define LOG(type) logger(type,__FILE__,__LINE__)

#define ENABLE_CONSOLE_STRATEGY() logger.UseConsoleStrategy()
#define ENABLE_FILE_STRATEGY() logger.UseFileStrategy()

}
